/**
 *
 */
package com.ozq.common.controller.action;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ozq.common.controller.form.QQForm;
import com.ozq.common.dao.entity.OauthConnectConfig;
import com.ozq.common.dao.entity.QQUser;
import com.ozq.common.dao.entity.SpringJson;
import com.ozq.common.util.CacheUtils;
import com.ozq.common.util.QQOauthUtils;
import com.ozq.common.util.UuidUtils;
import com.ozq.sys.dao.entity.SysText;
import com.ozq.sys.dao.entity.SysUser;
import com.ozq.sys.service.inter.SysTextService;
import com.ozq.sys.service.inter.SysUserService;

/**
 * <QQ登录>
 * <p>
 * <首页把控>
 * 
 * @author 欧增奇
 * @version [版本号, 2017年8月22日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Controller
@RequestMapping("login/qq")
public class QQLoginController
{
    static Logger logger = LoggerFactory.getLogger(QQLoginController.class);

    /**
     * 请求
     */
    @Autowired
    private CloseableHttpClient httpClient;

    /**
     * 请求的基本配置
     */
    @Autowired
    private RequestConfig config;

    /**
     * json转换
     */
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 用户服务
     */
    @Autowired
    private SysUserService sysUserService;

    /**
     * 内容服务
     */
    @Autowired
    private SysTextService sysTextService;

    /**
     * 使用QQ登录-获取用户信息
     */
    @ResponseBody
    @RequestMapping(value = "get", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public SpringJson loginQqGet(HttpServletRequest request, QQForm qqForm)
    {
        if (logger.isDebugEnabled())
        {
            logger.debug("debug qqForm:{}", qqForm);
        }
        SpringJson json = new SpringJson(false);
        OauthConnectConfig oauthConnectConfig = (OauthConnectConfig) CacheUtils.get(qqForm.getState());
        if (oauthConnectConfig != null)
        {
            json.setCode(SpringJson.SUCCESS);
            json.setData(oauthConnectConfig.getSysUser());
        }
        CacheUtils.remove(qqForm.getState());
        return json;
    }

    /**
     * 使用QQ登录-跳转
     */
    @RequestMapping("to")
    public String loginQqTo(HttpServletRequest request, QQForm qqForm)
    {
        if (logger.isDebugEnabled())
        {
            logger.debug("debug qqForm:{}", qqForm);
        }

        OauthConnectConfig oauthConnectConfig = new OauthConnectConfig();
        oauthConnectConfig.setUrl(qqForm.getUrl());
        return "redirect:" + QQOauthUtils.getAuthorizeUrl(oauthConnectConfig);
    }

    /**
     * 使用QQ登录-回调执行
     */
    @RequestMapping("do")
    public String loginQqDo(HttpServletRequest request, QQForm qqForm)
    {
        if (logger.isDebugEnabled())
        {
            logger.debug("debug qqForm:{}", qqForm);
        }

        // 验证回调是否成功
        if (qqForm.getUsercancel() != 0)
        {
            request.setAttribute("message", "QQ登录失败，用户取消！");
            return "common/error";
        }
        OauthConnectConfig oauthConnectConfig = (OauthConnectConfig) CacheUtils.get(qqForm.getState());
        if (oauthConnectConfig == null)
        {
            request.setAttribute("message", "QQ登录失败，已过期(5分钟内有效)！");
            return "common/error";
        }
        if (!StringUtils.equals(qqForm.getState(), oauthConnectConfig.getState()))
        {
            request.setAttribute("message", "QQ登录失败，非法操作！");
            return "common/error";
        }

        try
        {
            HttpPost httpPost = new HttpPost(QQOauthUtils.ACCESS_TOKEN_URL);
            // 加入配置信息
            httpPost.setConfig(config);

            // 参数
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            // grant_type 必须 授权类型，在本步骤中，此值为“authorization_code”。
            list.add(new BasicNameValuePair("grant_type", "authorization_code"));
            // client_id 必须 申请QQ登录成功后，分配给网站的appid。
            list.add(new BasicNameValuePair("client_id", QQOauthUtils.APP_ID));
            // client_secret 必须 申请QQ登录成功后，分配给网站的appkey。
            list.add(new BasicNameValuePair("client_secret", QQOauthUtils.APP_KEY));
            // code 必须 上一步返回的authorization code。
            list.add(new BasicNameValuePair("code", qqForm.getCode()));
            // redirect_uri 必须 与上面一步中传入的redirect_uri保持一致。
            list.add(new BasicNameValuePair("redirect_uri", QQOauthUtils.REDIRECT_URI));

            // 构造from表单对象
            UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");

            // 把表单放到post里
            httpPost.setEntity(urlEncodedFormEntity);

            // 发起请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            // 响应码
            Integer code = response.getStatusLine().getStatusCode();
            // 响应体
            String body = EntityUtils.toString(response.getEntity(), "UTF-8");

            if (code == HttpServletResponse.SC_OK)
            {
                Map<String, String> map = QQOauthUtils.toMap(body);
                String accessToken = map.get("access_token");

                // 获取OpenID
                httpPost.setURI(URI.create(QQOauthUtils.OPEN_ID_URL));
                list = new ArrayList<NameValuePair>();
                list.add(new BasicNameValuePair("access_token", accessToken));
                urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");
                // 把表单放到post里
                httpPost.setEntity(urlEncodedFormEntity);
                response = httpClient.execute(httpPost);
                // 响应码
                code = response.getStatusLine().getStatusCode();
                // 响应体
                body = EntityUtils.toString(response.getEntity(), "UTF-8");

                if (code == HttpServletResponse.SC_OK)
                {
                    // callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
                    String openId = body.split("\",\"openid\":\"")[1].split("\"")[0];

                    // 获取该用户是否存在
                    SysUser sysUser = new SysUser();
                    sysUser.setOpenId(openId);
                    sysUser = sysUserService.find(sysUser);
                    if (sysUser != null)
                    {
                        sysUser.setUserLastTime(new Date());
                        sysUserService.update(sysUser);
                        oauthConnectConfig.setSysUser(sysUser);
                        CacheUtils.put(oauthConnectConfig.getState(), oauthConnectConfig);
                        return "redirect:" + oauthConnectConfig.getUrl() + (oauthConnectConfig.getUrl().indexOf("?") == -1 ? "?" : "&") + "state=" + oauthConnectConfig.getState();
                    }

                    // 获取 用户信息 首次
                    httpPost.setURI(URI.create(QQOauthUtils.GET_USER_INFO_URL));
                    list = new ArrayList<NameValuePair>();
                    list.add(new BasicNameValuePair("access_token", accessToken));
                    list.add(new BasicNameValuePair("oauth_consumer_key", QQOauthUtils.APP_ID));
                    list.add(new BasicNameValuePair("openid", openId));
                    urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");
                    // 把表单放到post里
                    httpPost.setEntity(urlEncodedFormEntity);
                    response = httpClient.execute(httpPost);
                    // 响应码
                    code = response.getStatusLine().getStatusCode();
                    // 响应体
                    body = EntityUtils.toString(response.getEntity(), "UTF-8");

                    if (code == HttpServletResponse.SC_OK)
                    {
                        QQUser qqUser = objectMapper.readValue(body, QQUser.class);

                        if (qqUser.getRet() != 0)
                        {
                            request.setAttribute("message", "QQ登录失败，" + qqUser.getMsg());
                            return "common/error";
                        }

                        // 自动注册用户
                        sysUser = new SysUser();
                        sysUser.setUserCode(UuidUtils.shortUuid());
                        sysUser.setTextCode(UuidUtils.shortUuid());
                        sysUser.setUserNickName(qqUser.getNickname());
                        sysUser.setOpenId(openId);
                        // 支持https://
                        sysUser.setUserFigureUrl(StringUtils.removeStart(qqUser.getFigureurl_qq_1(), "http:"));

                        SysText sysText = new SysText();
                        sysText.setTextCode(sysUser.getTextCode());
                        sysText.setTextContent(body);

                        sysTextService.add(sysText);
                        sysUserService.add(sysUser);

                        oauthConnectConfig.setSysUser(sysUser);
                        CacheUtils.put(oauthConnectConfig.getState(), oauthConnectConfig);
                        return "redirect:" + oauthConnectConfig.getUrl() + (oauthConnectConfig.getUrl().indexOf("?") == -1 ? "?" : "&") + "state=" + oauthConnectConfig.getState();
                    }
                }
            } else
            {
                request.setAttribute("message", "QQ登录失败，认证失败！");
            }
        } catch (UnsupportedEncodingException e1)
        {
            logger.error("error:{}\n {}", e1.getMessage(), e1.getStackTrace());
        } catch (ClientProtocolException e)
        {
            logger.error("error:{}\n {}", e.getMessage(), e.getStackTrace());
        } catch (IOException e)
        {
            logger.error("error:{}\n {}", e.getMessage(), e.getStackTrace());
        }
        request.setAttribute("message", "QQ登录失败，获取用户信息失败！");
        return "common/error";
    }

}
